package uk.ac.rothamsted;

import static org.junit.Assert.assertTrue;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.junit.Test;

import uk.ac.rothamsted.utils.ArrayKey;

import com.google.common.collect.BiMap;


public class MainTestPartA{

	@Test
	public void test() throws IOException, ClassNotFoundException, InterruptedException {
		InParanoid inParanoid = new InParanoid(50, 50); // this sets the score and overlap cutoff at 50 for each.
		long start = System.currentTimeMillis();



		//load all data from blast output files.
		Map<ArrayKey<String>, BlastData> dataAA = inParanoid.readfile("src/test/resources/blastParsed/cerevisiae.fa-cerevisiae.fa");
		System.out.println("loaded first file");
		Map<ArrayKey<String>, BlastData> dataAB = inParanoid.readfile("src/test/resources/blastParsed/cerevisiae.fa-pombe.fa");
		System.out.println("loaded second file");
		Map<ArrayKey<String>, BlastData> dataBA = inParanoid.readfile("src/test/resources/blastParsed/pombe.fa-cerevisiae.fa");
		System.out.println("loaded third file");
		Map<ArrayKey<String>, BlastData> dataBB = inParanoid.readfile("src/test/resources/blastParsed/pombe.fa-pombe.fa");
		System.out.println("loaded fourth file");


		assertTrue(!dataAA.isEmpty());
		assertTrue(!dataAB.isEmpty());
		assertTrue(!dataBA.isEmpty());
		assertTrue(!dataBB.isEmpty());

		System.out.print("loadData - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s");
		start = System.currentTimeMillis();




		//generate species lists from original fasta files.
		List<Object> speciesAPair = inParanoid.listFastaSpecies("src/test/resources/blastParsed/cerevisiae.fa");
		@SuppressWarnings("unchecked")
		Set<String> speciesA = (Set<String>)speciesAPair.get(0);
		@SuppressWarnings("unchecked")
		BiMap<Integer, String> speciesMapA = (BiMap<Integer, String>)speciesAPair.get(1);

		List<Object> speciesBPair = inParanoid.listFastaSpecies("src/test/resources/blastParsed/pombe.fa");
		@SuppressWarnings("unchecked")
		Set<String> speciesB = (Set<String>)speciesBPair.get(0);
		@SuppressWarnings("unchecked")
		BiMap<Integer, String> speciesMapB = (BiMap<Integer, String>)speciesBPair.get(1);

		System.out.print("\nList Species - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s");
		start = System.currentTimeMillis();





		//combine blast output of A against B and B against A in one file
		Map<ArrayKey<String>, BlastData> dataABA = new HashMap<ArrayKey<String>, BlastData>();
		dataABA.putAll(dataAB);
		dataABA.putAll(dataBA);
		dataAB = null;
		dataBA = null;
		System.gc();

		System.out.print("create dataABA - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s");
		start = System.currentTimeMillis();




		//calculate average of each hit.

		Map<ArrayKey<String>, BlastData> avgAA = inParanoid.averageSequences(dataAA, speciesA, speciesMapA, speciesMapA);
		dataAA =null;
		System.gc();
		Map<ArrayKey<String>, BlastData> avgAB = inParanoid.averageSequences(dataABA, speciesA, speciesMapA, speciesMapB);
		dataABA = null;
		System.gc();
		Map<ArrayKey<String>, BlastData> avgBB = inParanoid.averageSequences(dataBB, speciesB, speciesMapB, speciesMapB);
		dataBB = null;
		System.gc();


		//		for(Entry<ArrayKey<String>, BlastData> iter: avgAB.entrySet()){
		//			System.out.println(iter.getValue());
		//		}


		//	System.out.print(avgAB);

		assertTrue(!avgAA.isEmpty());
		assertTrue(!avgAB.isEmpty());
		assertTrue(!avgBB.isEmpty());
		System.out.println("\nNumber of averages in avgAA - " + avgAA.size());
		System.out.println("Number of averages in avgAB - " + avgAB.size());
		System.out.println("Number of averages in avgBB - " + avgBB.size());

		System.out.print("\nfind averages - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s");
		start = System.currentTimeMillis();



		//create a set containing all averaged hits.
		Set< BlastData> avgSet = new HashSet< BlastData>();	
		for(Entry<ArrayKey<String>, BlastData> ent : avgAA.entrySet()){
			avgSet.add(ent.getValue());
		}

		for(Entry<ArrayKey<String>, BlastData> ent : avgAB.entrySet()){
			avgSet.add(ent.getValue());
		}

		for(Entry<ArrayKey<String>, BlastData> ent : avgBB.entrySet()){
			avgSet.add(ent.getValue());
		}



		//		speciesA = inParanoid.listSpecies(avgAA);
		//		speciesB = inParanoid.listSpecies(avgBB);
		//		assertTrue(!speciesA.isEmpty());
		//		assertTrue(!speciesB.isEmpty());


		System.out.print("List Species again - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s");
		start = System.currentTimeMillis();




		//find best hits
		Set<BlastData> bestHitsABSet = inParanoid.bestHit(avgAB, speciesA, speciesB);
		//bestHits.addAll(inParanoid.bestHit(avgAB, speciesA, speciesB));
		//bestHits.addAll(inParanoid.bestHit(avgBB, speciesB, speciesB));
		List<BlastData> bestHitsAB = new ArrayList<BlastData>(bestHitsABSet);
		Collections.sort(bestHitsAB);

		System.out.print("Find Best Hits - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s");
		start = System.currentTimeMillis();



		//		System.out.println("\n" + bestHitsAB +"\n");
		System.out.println("\nNumberof BestHits - " + bestHitsAB.size());





		//save all data to be used in part 2
		FileOutputStream avgSetoutStream = new FileOutputStream ("src/test/resources/temp/avgSet.data");
		FileOutputStream bestHitsABOutStream = new FileOutputStream ("src/test/resources/temp/BestHitsAB.data");
		FileOutputStream speciesAoutStream = new FileOutputStream ("src/test/resources/temp/speciesA.data");
		FileOutputStream speciesBoutStream = new FileOutputStream ("src/test/resources/temp/speciesB.data");

		ObjectOutputStream avgSetout = new ObjectOutputStream (avgSetoutStream);
		ObjectOutputStream bestHitsABOut = new ObjectOutputStream (bestHitsABOutStream);
		ObjectOutputStream speciesAout = new ObjectOutputStream (speciesAoutStream);
		ObjectOutputStream speciesBout = new ObjectOutputStream (speciesBoutStream);

		avgSetout.writeObject (avgSet);
		bestHitsABOut.writeObject (bestHitsAB);
		speciesAout.writeObject (speciesA);
		speciesBout.writeObject (speciesB);


		System.out.print("\nFinished Part 1 - ");
		System.out.print((System.currentTimeMillis()-start)/1000F);
		System.out.println(" s\n\n");



		//print out list of besthits
				for(BlastData iter: bestHitsAB){
					System.out.println(iter);
				}

		//System.out.println("\n\n\nPart 2\n");

		//		MainTestPartB testPart2 = new MainTestPartB();
		//		testPart2.test();

	}
}
